﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Infrastructure.ObjectModel;
using Microsoft.Xna.Framework.Input;
using Infrastructure.Managers;
using Infrastructure.ServiceInterfaces;
using Infrastructure.ObjectModel.Animations.ConcreteAnimations;

namespace B10_Ex02_EladLebovitch_034695114.ObjectModel
{
    public class Menu : CompositeDrawableComponent<MenuItem>
    {
        private Color k_ActiveColor = Color.Yellow;
        private Color k_UnActiveColor = Color.Red;

        public event EventHandler<MenuEventArgs> MenuItemEntered;
        protected void OnMenuItemEntered(int i_ItemIndex)
        {
            if (MenuItemEntered != null)
            {
                MenuItemEntered(this, new MenuEventArgs(i_ItemIndex, Keys.Enter));
            }
        }

        public event EventHandler<MenuEventArgs> MenuItemPgUp;
        protected void OnMenuItemPgUp(int i_ItemIndex)
        {
            if (MenuItemPgUp != null)
            {
                MenuItemPgUp(this, new MenuEventArgs(i_ItemIndex, Keys.PageUp));
            }
        }

        public event EventHandler<MenuEventArgs> MenuItemPgDown;
        protected void OnMenuItemPgDown(int i_ItemIndex)
        {
            if (MenuItemPgDown != null)
            {
                MenuItemPgDown(this, new MenuEventArgs(i_ItemIndex, Keys.PageDown));
            }
        }
        
        public MenuItem this[int Menuindex]
        {
            get
            {
                List<MenuItem> lst = this.ToList();
                return lst[Menuindex];
            }
        }

        private Sprite m_Title;
        public string AssetName
        {
            get;
            set;
        }

        public int NemberOfItems
        {
            get;
            set;
        }

        public int ItemHeight
        {
            get;
            set;
        }

        public IInputManager InputMgr
        {
            get
            { 
                return Game.Services.GetService(typeof(IInputManager)) as IInputManager;
            }
        }

        private MenuItem m_ActiveItem;
        private MenuItem ActiveItem
        {
            get
            {
                return m_ActiveItem;
            }
            set
            {
                if (m_ActiveItem != null)
                {
                    m_ActiveItem.TintColor = k_UnActiveColor;
                    m_ActiveItem.Animations.Reset();
                    m_ActiveItem.Animations.Remove("Pulse");
                    m_ActiveItem.Animations.Enabled = false;
                }

                m_ActiveItem = value;

                if (m_ActiveItem != null)
                {
                    (Game.Services.GetService(typeof(ISoundManeger)) as ISoundManeger).PlayCue("Menu");
                    m_ActiveItem.TintColor = k_ActiveColor;
                    m_ActiveItem.Animations.Add(new PulseAnimation("Pulse", TimeSpan.Zero, 1.10f, 0.7f));
                    m_ActiveItem.Animations.Enabled = true;
                }
            }
        }

        public Menu(string i_AssetName, Game i_Game, int i_NumberOfItems, int i_ItemHeight)
            : base(i_Game)
        {
            AssetName = i_AssetName;
            NemberOfItems = i_NumberOfItems;
            ItemHeight = i_ItemHeight;
            m_Title = new Sprite(i_AssetName, i_Game);

            for (int i = 0; i < NemberOfItems; i++)
            {
                MenuItem item = new MenuItem(
                    AssetName,
                    Game);
                base.Add(item);
                item.TintColor = k_UnActiveColor;
                item.MouseOver += new EventHandler(item_MouseOver);
                item.MouseLeftClicked += new EventHandler(item_MouseLeftClicked);
            }
        }

        private void item_MouseLeftClicked(object sender, EventArgs e)
        {
            List<MenuItem> lst = this.ToList();
            int index = lst.FindIndex(itm => itm == sender);
            this.OnMenuItemEntered(index);
        }

        private void item_MouseOver(object sender, EventArgs e)
        {
            if (ActiveItem != sender)
            {
                ActiveItem = (MenuItem)sender;
            }
        }

        public override void Initialize()
        {
            m_Title.Initialize();
            base.Initialize();
            m_Title.SourceRectangle = new Rectangle(0, 0, m_Title.Texture.Width, ItemHeight);
            m_Title.PositionOfOrigin = new Vector2(
                this.CenterOfViewPort.X,
                m_Title.SourceRectangle.Height);
            m_Title.PositionOrigin = m_Title.SourceRectangleCenter;
            
            for (int i = 0; i < NemberOfItems; i++)
            {
                MenuItem item = this.ToList()[i];
                item.SourceRectangle = new Rectangle(
                        0,
                        ItemHeight * (i + 1),
                        m_Title.Texture.Width,
                        ItemHeight);
                item.PositionOfOrigin = new Vector2(
                    this.CenterOfViewPort.X,
                this.CenterOfViewPort.Y - (this.Count * ItemHeight) + ((i + 2) * ItemHeight * 1.1f) + ItemHeight);

                item.PositionOrigin = item.SourceRectangleCenter;
                item.RotationOrigin = item.SourceRectangleCenter;
                
            }

            ActiveItem = this[0];           
        }

        protected override void LoadContent()
        {    
            base.LoadContent();
        }

        public override void Draw(GameTime gameTime)
        {
            m_Title.Draw(gameTime);
            base.Draw(gameTime);
        }

        /// <summary>
        /// Handles menu keys
        /// </summary>
        /// <param name="gameTime"></param>
        public override void Update(GameTime gameTime)
        {
            m_Title.Update(gameTime);
            if (InputMgr.KeyPressed(Keys.Up))
            {
                List<MenuItem> lst = this.ToList();
                int index = lst.FindIndex(itm => itm == ActiveItem);
                if (index == 0)
                {
                    index = this.Count - 1;
                }
                else
                {
                    index = index - 1;
                }

                ActiveItem = lst[index];
            }
            else if (InputMgr.KeyPressed(Keys.Down))
            {
                List<MenuItem> lst = this.ToList();
                int index = lst.FindIndex(itm => itm == ActiveItem);
                ActiveItem = lst[Math.Abs((index + 1) % lst.Count)];
            }
            else if (InputMgr.KeyPressed(Keys.PageUp)  || InputMgr.ScrollWheelDelta > 0)
            {
                List<MenuItem> lst = this.ToList();
                int index = lst.FindIndex(itm => itm == ActiveItem);
                this.OnMenuItemPgUp(index);
            }
            else if (InputMgr.KeyPressed(Keys.PageDown) || InputMgr.ScrollWheelDelta < 0)
            {
                List<MenuItem> lst = this.ToList();
                int index = lst.FindIndex(itm => itm == ActiveItem);
                this.OnMenuItemPgDown(index);
            }
            else if (InputMgr.KeyPressed(Keys.Enter))
            {
                List<MenuItem> lst = this.ToList();
                int index = lst.FindIndex(itm => itm == ActiveItem);
                this.OnMenuItemEntered(index);
            }

            base.Update(gameTime);
        }
    }

    public class MenuEventArgs : EventArgs
    {
        public int MenuItemIndex
        {
            get;
            private set;
        }

        public Keys KeyPressed
        {
            get;
            private set;
        }

        public MenuEventArgs() : base()
        {
        }

        public MenuEventArgs(int i_ItemIndex, Keys i_KeyPressed) : this()
        {
            MenuItemIndex = i_ItemIndex;
            KeyPressed = i_KeyPressed;
        }
    }
}
